/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hextd.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author hylke
 */
public class NetworkConnection implements LineListener {

	private Socket remote;
	private ArrayList<LineListener> listeners;
	private PrintWriter pw;
	private BufferedReader br;
	private InputWaiter waiter;
	private Thread thread;
	private int id = 0;
	private TimerTask flushTask;
	private Timer flushTimer;

	public NetworkConnection(Socket remote) throws IOException {
		this.remote = remote;
		listeners = new ArrayList<LineListener>();
		pw = new PrintWriter(new OutputStreamWriter(remote.getOutputStream(), "UTF-8"), false);
		br = new BufferedReader(new InputStreamReader(remote.getInputStream(), "UTF-8"));

		flushTimer = new Timer("flushTimer", true);
		flushTask = new TimerTask() {

			@Override
			public void run() {
				pw.flush();
			}
		};
		flushTimer.schedule(flushTask, 250, 250);
	}

	private void startListening() {
		waiter = new InputWaiter(br, this);
		thread = new Thread(waiter, "serverInputThread");
		thread.start();
	}

	public void sendLine(String line) {
		if (pw != null) {
			if (line.endsWith("\n")) {
				pw.println(line.substring(0, line.length() - 1));
			} else {
				pw.println(line);
			}
		}
	}

	@Override
	public void lineReceived(String line) {
		for (LineListener l : this.listeners) {
			l.lineReceived(line);
		}
	}

	@Override
	public void inputStopped() {
		for (LineListener l : this.listeners) {
			l.inputStopped();
		}
		close();
	}

	public void close() {
		try {
			if (flushTask != null) {
				flushTask.cancel();
				flushTask = null;
			}
			if (flushTimer != null) {
				flushTimer.cancel();
				flushTimer = null;
			}
			remote.close();
		} catch (IOException ex) {
			System.err.println("NetworkServer::stopServer: IOException when disconnecting client.");
			Logger.getLogger(NetworkServer.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	public void addLineListener(LineListener l) {
		if (this.listeners.size() == 0 && this.waiter == null) {
			this.startListening();
		}
		this.listeners.add(l);
	}

	public void removeLineListener(LineListener l) {
		this.listeners.remove(l);
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public InetAddress getRemoteAddress() {
		return remote.getInetAddress();
	}
}
